package com.zkh.myutils.io.excel.opcpack;

import java.io.IOException;
import java.io.OutputStream;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.zkh.myutils.io.excel.XMLParseException;
import com.zkh.myutils.io.excel.XMLParseUtils;
import com.zkh.myutils.io.excel.worksheet.style.Align;
import com.zkh.myutils.io.excel.worksheet.style.Alignment;
import com.zkh.myutils.io.excel.worksheet.style.Border;
import com.zkh.myutils.io.excel.worksheet.style.BorderStyle;
import com.zkh.myutils.io.excel.worksheet.style.CellXf;
import com.zkh.myutils.io.excel.worksheet.style.Font;
import com.zkh.myutils.io.excel.worksheet.style.StyleHandler;
import com.zkh.myutils.utils.Assert;
import com.zkh.myutils.utils.StringUtils;

/**
 * styles.xml生成
 * @author zkh
 */
class StyleXML extends ElementOperate{
	//样式处理器
	private StyleHandler styleHandler;
	//默认字体大小
	private Integer defaultFontSize = 11;

	/**
	 * 构造方法
	 * @param sheetList 数据，用来获取设置的样式
	 */
	public StyleXML(StyleHandler styleHandler) {
		this.styleHandler = styleHandler;
	}
	
	/**
	 * 获取格式化XML流并写入
	 * @return
	 * @throws IOException 
	 */
	public void writeFormatStream(OutputStream outputStream) throws IOException{
		//创建文档构建器
		try {
			DocumentBuilder builder = XMLParseUtils.createDocumentBuilder();
			//创建文档对象
			Document document = builder.newDocument();
			document.setXmlStandalone(true);
			//注入文档对象，用于创建节点元素
			injectDocument(document);
			//创建根节点
			Element root = document.createElement("styleSheet");
			//根节点挂在文档上
			document.appendChild(root);
			//属性
			root.setAttribute("xmlns", "http://schemas.openxmlformats.org/spreadsheetml/2006/main");
			//解析并写入样式数据
			renderDocument(root);
			//生成流转换器
			Transformer transformer = XMLParseUtils.createTransformer();
			//开始转换
			transformer.transform(new DOMSource(document), new StreamResult(outputStream));
			//刷新
			outputStream.flush();
		} catch (ParserConfigurationException | TransformerException e) {
			throw new XMLParseException(e);
		}
	}
	
	/**
	 * 解析并写入样式数据
	 * @param root 根节点
	 */
	private void renderDocument(Element root) {
		/** numFmts不设置，使用内置属性（0：普通文本，14：日期，22：日期时间） **/
		
		/** fonts字体（count="2"）**/
		//字体样式
		List<Font> fontList = styleHandler.getFontList();
		//处理数据
		Element fonts = createWithAttrs(root, "fonts", "count", Integer.toString(1 + fontList.size()));
		//默认样式
		createElementsWithVal(createWithAttrs(fonts, "font"), "sz", "11", "name", "宋体", "family", "2");
		//遍历样式
		for(Font font: fontList) {
			//创建节点
			Element elem = createWithAttrs(fonts, "font");
			//设置样式（family暂时不知作用）
			Assert.doIfTrue(font.isBold(), ()->createWithAttrs(elem, "b"));	//加粗
			Assert.doIfTrue(font.isItalic(), ()->createWithAttrs(elem, "i"));	//斜体
			Assert.doIfTrue(font.isUnderline(), ()->createWithAttrs(elem, "u"));	//下划线
			createElementsWithVal(elem, "sz", Assert.getOrDefault(font.getFontSize(), defaultFontSize).toString());	//字体大小
			Assert.doIfNotNull(font.getFontFamily(), ff->createElementsWithVal(elem, "name", ff));	//字体
			Assert.doIfNotNull(font.getColor(), c->createWithAttrs(elem, "color", "rgb", c.replace("#", "")));	//字体颜色
		}
		/** fills填充样式 **/
		//背景样式
		List<String> bgColorList = styleHandler.getBgColorList();
		//创建节点
		Element fills = createWithAttrs(root, "fills", "count", Integer.toString(1 + bgColorList.size()));
		//默认样式（自定义填充样式必须从第3个开始，第一第二都不会生效）
		createWithAttrs(createWithAttrs(fills, "fill"), "patternFill", "patternType", "none");
		createWithAttrs(createWithAttrs(fills, "fill"), "patternFill", "patternType", "gray125");
		//遍历样式
		for(String bgc: bgColorList) {
			//patternFill节点
			Element ptn = createWithAttrs(createWithAttrs(fills, "fill"), "patternFill", "patternType", "solid");
			//背景色（属性rgb也可以使用indexed属性替换，值为预制颜色值索引）
			createWithAttrs(ptn, "fgColor", "rgb", bgc.replace("#", ""));
		}
		
		/** borders边框样式 **/
		//边框样式
		List<Border> borderList = styleHandler.getBorderList();
		//创建节点
		Element borders = createWithAttrs(root, "borders", "count", Integer.toString(1 + borderList.size()));
		//默认样式
		Element border = createWithAttrs(borders, "border");
		//left，right，top，bottom，diagonal（对角线）
		createElements(border, "left", "right", "top", "bottom", "diagonal");
		//遍历边框
		for(Border b: borderList) {
			//当前节点
			Element elem = createWithAttrs(borders, "border");
			//处理边框
			renderBorder(elem, "left", b.getLeft());
			renderBorder(elem, "right", b.getRight());
			renderBorder(elem, "top", b.getTop());
			renderBorder(elem, "bottom", b.getBottom());
			createWithAttrs(elem, "diagonal");
		}
		
		/** cellStyleXfs样式组合，给默认设置即可，不作特殊设置 **/
		Element cellStyleXfs = createWithAttrs(root, "cellStyleXfs", "count", "1");
		//xf
		Element xf = createWithAttrs(cellStyleXfs, "xf", "numFmtId", "0", "fontId", "0", "fillId", "0", "borderId", "0");
		//垂直居中
		createWithAttrs(xf, "alignment", "vertical", "center");
		
		/** cellXfs单元格最终样式 **/
		//最终样式
		List<CellXf> cellXfList = styleHandler.getCellXlList();
		//内置日期和日期时间
		Element cellXfs = createWithAttrs(root, "cellXfs", "count", Integer.toString(3 + cellXfList.size()));
		//第一行空样式（第一行必须是空样式，任何样式放在第一行，都不会生效）
		createWithAttrs(cellXfs, "xf", "numFmtId", "0", "fontId", "0", "fillId", "0", "borderId", "0", "xfId", "0");
		//日期节点
		Element dateXf = createWithAttrs(cellXfs, "xf", "numFmtId", "14", "fontId", "0", "fillId", "0", "borderId", "0", "xfId", "0", "applyNumberFormat", "1");
		//垂直居中
		createWithAttrs(dateXf, "alignment", "vertical", "center");
		//日期时间节点
		Element datetimeXf = createWithAttrs(cellXfs, "xf", "numFmtId", "22", "fontId", "0", "fillId", "0", "borderId", "0", "xfId", "0", "applyNumberFormat", "1");
		//垂直居中
		createWithAttrs(datetimeXf, "alignment", "vertical", "center");
		//遍历
		for(CellXf cellXf: cellXfList) {
			//创建xf
			Element xfNode = createWithAttrs(cellXfs, "xf", "numFmtId", Integer.toString(cellXf.getNumFmtId()), "fontId", Integer.toString(cellXf.getFontId()), "fillId", Integer.toString(cellXf.getFillId()), "borderId", Integer.toString(cellXf.getBorderId()), "xfId", Integer.toString(cellXf.getXfId()));
			//样式应用
			Assert.doIfTrue(cellXf.getFontId()>0, ()->xfNode.setAttribute("applyFont", "1"));
			Assert.doIfTrue(cellXf.getFillId()>0, ()->xfNode.setAttribute("applyFill", "1"));
			Assert.doIfTrue(cellXf.getBorderId()>0, ()->xfNode.setAttribute("applyBorder", "1"));
			//对齐方式
			Alignment alignment = cellXf.getAlignment();
			//存在
			if(alignment!=null) {
				//垂直
				Align v = alignment.getVertical();
				//水平
				Align h = alignment.getHorizontal();
				//存在（垂直居下是默认值，不用设置）
				if((v!=Align.CANCLE && v!=Align.VERTICAL_BOTTOM) || h!=Align.CANCLE) {
					//创建节点
					Element alignNode = createWithAttrs(xfNode, "alignment");
					//属性
					if(v!=Align.CANCLE && v!=Align.VERTICAL_BOTTOM) {
						alignNode.setAttribute("vertical", v.name);
					}
					if(h!=Align.CANCLE) {
						alignNode.setAttribute("horizontal", v.name);
					}
					//应用样式属性
					xfNode.setAttribute("applyAlignment", "1");
				}
			}
		}
	}
	
	/**
	 * 渲染边框
	 * @param parent 父节点
	 * @param nodeName 节点名称
	 * @param style 节点样式
	 */
	private void renderBorder(Element parent, String nodeName, BorderStyle style) {
		//样式为空
		if(style==null) {
			createWithAttrs(parent, nodeName);
		}else {
			//创建节点
			Element n = createWithAttrs(parent, nodeName, "style", style.isBold() ? "medium" : "thin");
			//边框颜色
			if(StringUtils.isNotEmpty(style.getColor())) {
				createWithAttrs(n, "color", "rgb", style.getColor().replace("#", ""));
			}
		}
	}
}
